#include "Measurer.h"

 int Measurer::count = 1;
 Measurer_Node *Measurer::root = 0;
 Measurer_Node *Measurer::myNode = 0;
 vector<float> Measurer::partitions;
 vector<ProSpace> Measurer::adj;
 vector<ProSpace> Measurer::adj2;
 vector<ProSpace> Measurer::org;
 vector<ProSpace> tmp;


//-------------------------------------------------------------------------------------------------------------
extern void getOriginalConfig(string varname,vector<ProSpace>&myorg);
extern int compare (const void * a, const void * b);
void Measurer::addToRoot(ProSpace* space){
	if(!root) {
		root = myNode = new Measurer_Node();
	}
	myNode->addSpace(space);
	Measurer::count++;
}
 void Measurer::updateTmpValue(int value, int op){
	for (int i=0; i< myNode->sizeOf();i++){
		myNode->getSpace(i).updateTmpValue(value,op);
		cout << myNode->getSpace(i);
		/*for(int j=0;j<3;j++){
			((ProSpace)root->getSpace(i)).output(j);
		}*/
	}
		
}
void Measurer::updateTmpValue(string varname, int op){
	
	for (int i=0; i< myNode->sizeOf();i++){
		myNode->getSpace(i).updateTmpValue(varname,op);
		cout << myNode->getSpace(i);
		//space->updateTmpValue(varname,op);	
		//root->updateSpace(space,i);
			//cout << space;	
	}
	
}
void Measurer::updateByTmp(string varname){
	for (int i=0; i<myNode->sizeOf(); i++){
		myNode->getSpace(i).updateByTmp(varname);
		cout << myNode->getSpace(i);
	}
		
}
void Measurer::updateByTmp(string from, string to){
	for (int i=0; i<myNode->sizeOf(); i++){
		myNode->getSpace(i).updateByTmp(from,to);
		cout << myNode->getSpace(i);
	}
}
ProSpace& Measurer::output(int index){
	return Measurer::root->getSpace(index);

}
ProSpace& Measurer::output(string varname){
	int index;
	
	index = ((ProSpace)Measurer::root->getSpace(0)).getIndex(varname);		
	
	return Measurer::root->getSpace(index);

}

float Measurer::measureEntropy(string varname){
	
	getOriginalProb(varname);
	adjustProSpace(varname);

	if (partitions.size()==0){
		return conditionEntropy();
	}
	else{
		// parition part
		return 0.0;
	}
	
}

void Measurer::getOriginalProb(string varname){

	//printf("%s\n", "print out the original data before processing");
	// get the original data using varname
	//for(int i=0; i< Measurer::count-1;i++){
		
		//ProSpace myspace = root->getSpace(i);		
		//ProSpace space2 = myspace.getVarSpace(varname);
		//int varvalue = myspace.getValue(space.getIndex(varname));
		//float p = space.getProbability();
		//tmp.push_back(ProSpace(varname, varvalue,p,1));		
	//	ProSpace space2 = 
	//	tmp.push_back(space2);
	//}
	getOriginalConfig(varname,tmp);

	// Print out the original data
	//for(int i=0; i< tmp.size(); i++){
	//	//ProSpace s = tmp[i];
	//	//printf("%d,%d,%d,%f\n", s.getValue(0),s.getValue(1),s.getValue(2), s.getProbability());
	////	cout << tmp[i];
	//}

	if(tmp.size()>0){
		org.push_back(tmp[0]);
		for(unsigned int i=1; i< tmp.size();i++){
			//ProSpace sp = org[org.size()-1];
			ProSpace sp2 = tmp[i];
			if(org[org.size()-1].getValue(0)==sp2.getValue(0)){
				org[org.size()-1].setProbability(org[org.size()-1].getProbability()+sp2.getProbability());
				//org[org.size()-1] = sp;
			}
			else{
				org.push_back(sp2);
			}
			
		}
	}

	// Print out the original data
	//printf("%s\n", "print out the original data after processing");
	for(int i=0; i< org.size(); i++){
		//ProSpace s = tmp[i];
		//printf("%d,%d,%d,%f\n", s.getValue(0),s.getValue(1),s.getValue(2), s.getProbability());
	//	cout << org[i];
	}


}

void  Measurer:: adjustProSpace(string varname){
	
	
	
	for(unsigned int i=0; i< Measurer::count-1;i++){
		
		adj.push_back((((ProSpace)Measurer::root->getSpace(i)).getVarSpace(varname)));		
	//	adj_arr = adj[i];
	}
	

	
	ProSpace* arr = new ProSpace[Measurer::count-1];
	ProSpace mytmp;
	for(int i=0;i< Measurer::count-1;i++){
		arr[i] = adj[i];
		//mytmp = adj[i];
		
	}

	ProSpace tmp;
	for(int i=0; i<Measurer::count-1;i++){
		for(int j=i; j<Measurer::count-1;j++){
			if(arr[i].getValue(0) > arr[j].getValue(0)){
				tmp= arr[i];
				(arr[i]) = (arr[j]);
				arr[j] = tmp;		
				
				
			}
		}
	}
	
	if(adj.size() > 0) {
		adj2.push_back(arr[0]);
		int v,v2 = 0;
		float p,p2;
		
		for(unsigned int i=1;i<adj.size();i++){
			v = arr[i].getValue(0);
			v2 = adj2[adj2.size()-1].getValue(0);
			p = arr[i].getProbability();
			p2 =adj2[adj2.size()-1].getProbability();
			if (v==v2){
				// direct assignment  without interference
				//ProSpace sp = adj2[adj2.size()-1];
				//sp.setProbability(p+p2);

				adj2[adj2.size()-1].setProbability(p+p2);
			}
			else{
				ProSpace tmp = arr[i];
				adj2.push_back(tmp);
			}

		}
	}

	
	delete[] arr;
	arr=0;

}
float Measurer::conditionEntropy(){
	float entropy =0.0;
	float pro = 1.0;
	int h,l;
	
	vector<ProSpace> jntSpace;
	// org is the initial distribution space of interested var l
	// adj2 is the final distribution space of interested var l'
	jointSpace(org,adj2,jntSpace);
	for(int i=0;i< jntSpace.size();i++){
		cout << jntSpace[i];
	}
	//printf("%s\n", "Print out the joint space data");
	//for(unsigned int i=0;i < org.size();i++){
	//	for(unsigned int j=0;j<adj2.size();j++){
	//	//	cout << org[j];
	//	//	cout << adj2[j];
	//		ProSpace space = org[i] + adj2[j];
	//		jntSpace.push_back(space);
	//	//cout << space;

	//	}
	//}
	//jointSpace(org,adj2,space)

	/*entropy for H(l,l')*/
	for(unsigned int i=0; i< jntSpace.size();i++){
		//pro = ((ProSpace)Measurer::root->getSpace(i)).getProbability();
		pro = jntSpace[i].getProbability();
		entropy += (float)(pro * log(1/pro)/log(2.0));
		//printf("prob = %f \n",pro);
		//printf("entropy = %f\n",entropy);
	}
	
	/*entropy for H(l,l') - H(l)*/
	for(unsigned int i=0; i< org.size();i++){
		pro = ((ProSpace)(org[i])).getProbability();
		entropy-=(float)(pro * log(1/pro)/log(2.0));
		//printf("prob = %f \n",pro);
		//printf("entropy = %f\n",entropy);
	}
	
	

	return entropy;
}
void Measurer::addPartition(float weight){
	partitions.push_back(weight);
}

void Measurer::jointSpace(vector<ProSpace> sp, vector<ProSpace>sp2,vector<ProSpace>& jntSpace){
	//printf("%s\n", "Print out the joint space data");
	for(unsigned int i=0;i < sp.size();i++){
		for(unsigned int j=0;j<sp2.size();j++){
			ProSpace space = sp[i] + sp2[j];
			jntSpace.push_back(space);
			//cout << space;

		}
	}
	
}

void Measurer::addLeftChildNode(ProSpace* space){
	myNode->addLeftChildNode(space);
}
void Measurer::addRightChildNode(ProSpace* space){
	myNode->addRightChildNode(space);
}

void Measurer::updateLeftNode(){
	myNode = myNode->getLeftNode();
}
void Measurer::updateRightNode(){
	myNode = (myNode->getParentNode())->getRightNode();
}
void Measurer::updateParent(){
	myNode = myNode->getParentNode();
}
void Measurer::updateNodeByChild(){

}
Measurer_Node* Measurer::getChildNode(){
	// it is a recursive function
	//from left to right

	if(myNode->isLeftNodeEmpty()){
		return myNode->getLeftNode();
	}
	else if(myNode->isRightNodeEmpty()){
		return myNode->getRightNode();
	}
	
}
